package com.jumi.microservice.service.logistics;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jumi.microservice.dto.logistics.AutoSpiltRequest;
import com.jumi.microservice.dto.logistics.GoodsEntity;
import com.jumi.microservice.dto.logistics.LogisticsPackage;
import com.jumi.microservice.dto.logistics.OrderInfoRequest;
import com.jumi.microservice.entity.LogisticsGoods;
import com.jumi.microservice.entity.OrderLogistics;
import com.jumi.microservice.entity.SpiltMergeSetup;
import com.jumi.microservice.enumerate.*;
import com.jumi.microservice.mapper.LogisticsGoodsMapper;
import com.jumi.microservice.mapper.OrderLogisticsMapper;
import com.jumi.microservice.mapper.SpiltMergeSetupMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author by mazhao
 * @Classname AutoSpiltOrderService
 * @Description TODO
 * @Date 2020/8/4 14:25
 */
@Service
public class AutoSpiltService {

    private static final Logger log = LoggerFactory.getLogger(AutoSpiltService.class);

    @Resource
    SpiltMergeSetupMapper spiltMergeSetupMapper;

    @Resource
    OrderRelatedService orderRelatedService;

    @Resource
    LogisticsGoodsMapper logisticsGoodsMapper;

    @Resource
    OrderLogisticsMapper orderLogisticsMapper;

    /**
     * 生成随机字符串位数
     */
    private static int len = 14;
    /**
     * 非自营标识
     */
    private static int noSelf = -88;
//    /**
//     * 组合商品
//     */
//    private static int isGroup = -66;
//
//    /**
//     * 是否海外
//     */
//    private static int isImport = -99;

    /**
     * 自动拆单
     *
     * @param request
     */
    public void autoSpiltOrder(AutoSpiltRequest request) {
        OrderInfoRequest orderInfoRequest = new OrderInfoRequest();
        BeanUtils.copyProperties(request, orderInfoRequest);
        log.info("自动拆单接收参数 [{}]", JSON.toJSONString(orderInfoRequest));
        LogisticsPackage logisticsPackage = orderRelatedService.getOrderPackage(orderInfoRequest);
        if (logisticsPackage == null) {
            return;
        }
        List<LogisticsPackage> result = autoSpiltByRules(autoSpiltByTag(autoSpiltByWareHouse(logisticsPackage)));
        //插入物流表
        addLogistics(result);
    }

    /**
     * 根据发货仓自动拆分
     *
     * @param param
     * @return
     */
    public Map<Integer, LogisticsPackage> autoSpiltByWareHouse(LogisticsPackage param) {
        log.info("自动拆单 开始-->");
        //每个包裹的商品
        List<GoodsEntity> goodsList = param.getList();
        Map<Integer, LogisticsPackage> map = new HashMap<>();
        //遍历每个包裹的所有商品
        for (GoodsEntity g : goodsList) {
            Integer key;
            if (g.getSelfFlag().equals(SelfFlagEnum.NO_SELF.getCode())) {
                key = noSelf;
            } else {
                key = g.getRealWarehouse();
            }
            if (map.containsKey(key)) {
                map.get(key).add(g);
                continue;
            }
            LogisticsPackage logisticsPackage = getLogisticsPackage(param);
            logisticsPackage.add(g);
            logisticsPackage.setIsGroup(g.getIsGroup());
            logisticsPackage.setLogisticsNo(getRandomString());
            logisticsPackage.setSelfFlag(g.getSelfFlag());
            logisticsPackage.setWarehouse(g.getRealWarehouse());
            map.put(key, logisticsPackage);
        }
        return map;
    }

    /**
     * 根据商品拆合单分类自动拆分
     *
     * @param paramMap
     * @return
     */
    public Map<Integer, LogisticsPackage> autoSpiltByTag(Map<Integer, LogisticsPackage> paramMap) {
        Map<Integer, LogisticsPackage> map = new HashMap<>();
        if (paramMap == null || paramMap.isEmpty()) {
            return map;
        }
        //遍历所有包裹
        for (Integer key : paramMap.keySet()) {
            if (key == noSelf
            ) {
                continue;
            }
            //每个包裹的商品
            List<GoodsEntity> goodsList = paramMap.get(key).getList();
            //遍历每个包裹的所有商品
            for (GoodsEntity g : goodsList) {
                if (map.containsKey(g.getGoodsLabel() + g.getRealWarehouse())) {
                    map.get(g.getGoodsLabel() + g.getRealWarehouse()).add(g);
                    continue;
                }
                LogisticsPackage logisticsPackage = getLogisticsPackage(paramMap.get(key));
                logisticsPackage.setGoodsLabel(g.getGoodsLabel());
                logisticsPackage.add(g);
                map.put(g.getGoodsLabel() + g.getRealWarehouse(), logisticsPackage);
            }
        }
        //将非自营添加进去
        if (paramMap.containsKey(noSelf)) {
            map.put(noSelf, paramMap.get(noSelf));
        }
        return map;
    }

    /**
     * 根据拆合单规则自动拆分
     *
     * @param paramMap
     * @return
     */
    public List<LogisticsPackage> autoSpiltByRules(Map<Integer, LogisticsPackage> paramMap) {
        List<LogisticsPackage> result = new ArrayList<>();
        if (paramMap == null || paramMap.isEmpty()) {
            return result;
        }
        Map<Integer, SpiltMergeSetup> spiltMergeSetupsMap = getAllSpiltMergeSetup();
        for (Integer key : paramMap.keySet()) {
            if (key == noSelf
            ) {
                continue;
            }
            List<GoodsEntity> goodsList = paramMap.get(key).getList();
            List<GoodsEntity> temp = new ArrayList<>(goodsList);
            for (GoodsEntity g : goodsList) {
                //判断商品是否有规则
                if (spiltMergeSetupsMap != null && spiltMergeSetupsMap.containsKey(g.getSpuId())) {
                    //获取该商品规则
                    SpiltMergeSetup spiltMergeSetup = spiltMergeSetupsMap.get(g.getSpuId());
                    g.setIsRule(IsRuleEnum.YES_RULE.getCode());
                    g.setIsAlone(spiltMergeSetup.getIsAlone());
                    g.setGoodsMaxAmount(spiltMergeSetup.getSpiltMergeCount());
                    if (spiltMergeSetup.getIsAlone().equals(IsAloneEnum.YES.getCode())
                            || (spiltMergeSetup.getIsAlone().equals(IsAloneEnum.NO.getCode())
                            && g.getGoodsAmount() > spiltMergeSetup.getSpiltMergeCount())) {
                        //计算单独发货时包裹的商品数量以及需要生成几个包裹
                        int packageCount = packageCount(g.getGoodsAmount(), spiltMergeSetup.getSpiltMergeCount());
                        for (int i = 1; i <= packageCount; i++) {
                            LogisticsPackage logisticsPackage = getLogisticsPackage(paramMap.get(key));
                            logisticsPackage.setLogisticsNo(getRandomString());
                            List<GoodsEntity> list = new ArrayList<>();
                            //修改每个包裹的商品单独发货数量
                            GoodsEntity goodsEntity = new GoodsEntity();
                            BeanUtils.copyProperties(g, goodsEntity);
                            goodsEntity.setIsRule(IsRuleEnum.YES_RULE.getCode());
                            goodsEntity.setIsAlone(spiltMergeSetup.getIsAlone());
                            goodsEntity.setGoodsMaxAmount(spiltMergeSetup.getSpiltMergeCount());
                            goodsEntity.setGoodsAmount(goodsCount(g.getGoodsAmount(), i, spiltMergeSetup.getSpiltMergeCount()));
                            list.add(goodsEntity);
                            logisticsPackage.setList(list);
                            logisticsPackage.setIsAlone(spiltMergeSetup.getIsAlone());
                            result.add(logisticsPackage);
                            temp.remove(g);
                        }
                    }
                }
            }
            if ((!temp.isEmpty() && !temp.equals(goodsList))) {
                LogisticsPackage logisticsPackage = getLogisticsPackage(paramMap.get(key));
                logisticsPackage.setLogisticsNo(getRandomString());
                logisticsPackage.setList(temp);
                result.add(logisticsPackage);
            } else if (temp.equals(goodsList)) {
                paramMap.get(key).setLogisticsNo(getRandomString());
                result.add(paramMap.get(key));
            }
        }
        //将非自营添加进去
        if (paramMap.containsKey(noSelf)) {
            result.add(paramMap.get(noSelf));
        }
        if (result.size() > 1) {
            for (LogisticsPackage l : result) {
                l.setSpiltMergeStatus(SpiltMergeStatusEnum.SPILT.getCode());
            }
        }
        log.info("自动拆单 结束--> {}",JSON.toJSONString(result));
        return result;
    }

/**
 * ===================================================================================================================
 */


    /**
     * 产生新包裹
     *
     * @param param
     * @return
     */
    public LogisticsPackage getLogisticsPackage(LogisticsPackage param) {
        LogisticsPackage logisticsPackage = new LogisticsPackage();
        logisticsPackage.setSpiltMergeStatus(param.getSpiltMergeStatus());
        logisticsPackage.setReceiverName(param.getReceiverName());
        logisticsPackage.setReceiverAddress(param.getReceiverAddress());
        logisticsPackage.setReceiverPhone(param.getReceiverPhone());
        logisticsPackage.setGoodsLabel(param.getGoodsLabel());
        logisticsPackage.setWarehouse(param.getWarehouse());
        logisticsPackage.setIsGroup(param.getIsGroup());
        return logisticsPackage;
    }

    /**
     * 发送请求物流相关表添加包裹物流数据
     *
     * @param paramList
     * @return
     */
    public void addLogistics(List<LogisticsPackage> paramList) {
        List<LogisticsGoods> logisticsGoodsList = new ArrayList<>();
        List<OrderLogistics> orderLogisticsList = new ArrayList<>();
        for (LogisticsPackage p : paramList) {
            OrderLogistics orderLogistics = new OrderLogistics();
            BeanUtils.copyProperties(p, orderLogistics);
            orderLogistics.setReceiverInfo(p.getReceiverPhone() + p.getReceiverAddress());
            orderLogisticsList.add(orderLogistics);
            for (GoodsEntity g : p.getList()) {
                LogisticsGoods logisticsGoods = new LogisticsGoods();
                BeanUtils.copyProperties(g, logisticsGoods);
                logisticsGoods.setLogisticsNo(orderLogistics.getLogisticsNo());
                logisticsGoodsList.add(logisticsGoods);
            }
        }
        if (!orderLogisticsList.isEmpty()) {
            orderLogisticsMapper.batchInsertLogistics(orderLogisticsList);
            if (!logisticsGoodsList.isEmpty()) {
                logisticsGoodsMapper.batchInsertGoods(logisticsGoodsList);
            }
        }
    }


    /**
     * 获取每个包裹商品数量
     *
     * @return
     */
    public int goodsCount(int goodsTotal, int index, int indexCount) {
        if (goodsTotal - index * indexCount < 0) {
            return goodsTotal - (index - 1) * indexCount;
        }
        return indexCount;
    }

    /**
     * 单独发货时获取包裹数量
     *
     * @param total
     * @param amount
     * @return
     */
    public int packageCount(int total, int amount) {
        if (total % amount == 0) {
            return total / amount;
        }
        return total / amount + 1;
    }

    /**
     * 获取所有SPU规则
     *
     * @return
     */
    public Map<Integer, SpiltMergeSetup> getAllSpiltMergeSetup() {
        Map<Integer, SpiltMergeSetup> map = new HashMap<>();
        QueryWrapper<SpiltMergeSetup> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("del_flag", 0).eq("status", 1);
        List<SpiltMergeSetup> list = spiltMergeSetupMapper.selectList(queryWrapper);
        if (list.isEmpty()) {
            return null;
        }
        for (SpiltMergeSetup spiltMergeSetup : list) {
            map.put(spiltMergeSetup.getSpuId(), spiltMergeSetup);
        }
        return map;
    }

    /**
     * 生成指定长度不重复随机字符串
     *
     * @return
     */
    public synchronized String getRandomString() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String[] baseString = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
                "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
        Random random = new Random();
        int length = baseString.length;
        String randomString = "";
        for (int i = 0; i < length; i++) {
            randomString += baseString[random.nextInt(length)];
        }
        random = new Random(System.currentTimeMillis());
        String resultStr = "";
        for (int i = 0; i < len; i++) {
            resultStr += randomString.charAt(random.nextInt(randomString.length() - 1));
        }
        return "JM" + simpleDateFormat.format(new Date()) + resultStr;
    }

}
